package de.hdu.pms.ctrl;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import de.hdu.pms.dao.ArbeitstagDao;
import de.hdu.pms.dao.FeiertageDao;
import de.hdu.pms.dao.KrankheitDao;
import de.hdu.pms.dao.MitarbeiterDao;
import de.hdu.pms.dao.PausenDao;
import de.hdu.pms.dao.UrlaubDao;
import de.hdu.pms.lib.ArbeitstagOutput;
import de.hdu.pms.model.Arbeitstag;
import de.hdu.pms.model.Mitarbeiter;
import de.hdu.pms.model.Pausen;

@Controller
public class ArbeitszeitController {
	private ArbeitstagDao arbeitstagDao = null;
	private PausenDao pausenDao = null;
	private MitarbeiterDao mitarbeiterDao = null;
	private FeiertageDao feiertageDao = null;
	private UrlaubDao urlaubDao = null;
	private KrankheitDao krankheitDao = null;
	
	public void setKrankheitDao(KrankheitDao krankheitDao) {
		this.krankheitDao = krankheitDao;
	}

	public void setFeiertageDao(FeiertageDao feiertageDao) {
		this.feiertageDao = feiertageDao;
	}

	public void setUrlaubDao(UrlaubDao urlaubDao) {
		this.urlaubDao = urlaubDao;
	}

	public void setMitarbeiterDao(MitarbeiterDao mitarbeiterDao) {
		this.mitarbeiterDao = mitarbeiterDao;
	}

	public void setPausenDao(PausenDao pausenDao) {
		this.pausenDao = pausenDao;
	}

	public void setArbeitstagDao(ArbeitstagDao arbeitstagDao){
		this.arbeitstagDao = arbeitstagDao;
	}

	/***
	 * 
	 * <p>
	 * View working times
	 * </p>
	 * <p>
	 * Expected HTTP GET and request '/Arbeitszeit.html'.
	 * </p>
	 * <p>
	 * Linked Viewname to 'arbeitszeit.jsp'
	 * 
	 * @param request
	 * @param atag_datum
	 * @return
	 */
	@RequestMapping(value="/Arbeitstzeit.html", method=RequestMethod.GET)
	public ModelAndView arbeitszeit(HttpServletRequest request, String atag_datum){
		HttpSession session = request.getSession();
		Integer mit_id = Integer.parseInt(session.getAttribute("user").toString());

		ModelAndView mv = new ModelAndView();
		
		mv.addObject("title", "Arbeitszeit");

		Calendar datum = Calendar.getInstance();
		Date heute = datum.getTime();
		SimpleDateFormat tmp = new SimpleDateFormat("dd.MM.yyyy");
		try{
			datum.setTime(tmp.parse(atag_datum));
		}catch (Exception e) {
			;
		}

		//Arbeitstag
		mv.addObject("tag", this.getTag(datum.getTime(), mit_id));

		//Soll
		Mitarbeiter mitarbeiter = mitarbeiterDao.findById(mit_id);
		if(mitarbeiter.getBasis().getId() == 1){
			//Tagessoll
			int soll_tag;
			try{
				soll_tag = mitarbeiter.getMit_sollstunden();
			}catch (Exception e) {
				soll_tag = 0;
			}
			mv.addObject("soll_tag", soll_tag+" Stunden");
			mv.addObject("soll_monat", this.getMonatSoll(datum, mit_id)+" Stunden");
		}else{
			//Monatssoll + sonst
			mv.addObject("soll_tag", "-");
			mv.addObject("soll_monat", mitarbeiter.getMit_sollstunden()+" Stunden");
		}
		
		//Pausen
		try{
			datum.setTime(tmp.parse(atag_datum));
		}catch (Exception e) {
			datum.setTime(heute);
		}
		Arbeitstag arbeitstag = arbeitstagDao.findByDate(datum.getTime(), mit_id);
		List<ArbeitstagOutput> lPausen = new ArrayList<ArbeitstagOutput>();
		if(arbeitstag != null){
			List<Pausen> pausen = pausenDao.findByAtag(arbeitstag.getId());
			if(pausen != null){
				for(Pausen p : pausen){
					ArbeitstagOutput pause = new ArbeitstagOutput();
					pause.setAtag_von(this.formatZeit(p.getPause_start().getTime(), 2));
					if(p.getPause_stop()!=null){
						pause.setAtag_bis(this.formatZeit(p.getPause_stop().getTime(), 2));
					}
					lPausen.add(pause);
				}
			}else{
				ArbeitstagOutput pause = new ArbeitstagOutput();
				pause.setAtag_von("keine Pausen");
				lPausen.add(pause);
			}
		}else{
			ArbeitstagOutput pause = new ArbeitstagOutput();
			pause.setAtag_von("keine Pausen");
			lPausen.add(pause);
		}
		mv.addObject("pausen",lPausen);
		//Monat
		Calendar monatStart = Calendar.getInstance();
		Calendar monatEnd = Calendar.getInstance();
		monatStart.set(Calendar.DAY_OF_MONTH, Calendar.getInstance().getActualMinimum(Calendar.DAY_OF_MONTH));
		monatEnd.set(Calendar.DAY_OF_MONTH, Calendar.getInstance().getActualMaximum(Calendar.DAY_OF_MONTH));
		
		List<Arbeitstag> monat = arbeitstagDao.findBySpan(monatStart.getTime(), monatEnd.getTime(), mit_id);
		List<ArbeitstagOutput> lMonat = new ArrayList<ArbeitstagOutput>();
		long monat_zeit = 0;
		for(Arbeitstag atag : monat){
			ArbeitstagOutput tag = this.getTag(atag.getAtag_datum(), mit_id);
			monat_zeit += tag.getZeit();
			lMonat.add(tag);
		}
		
		mv.addObject("monat_zeit", this.formatZeit(monat_zeit, 4));
		mv.addObject("datum", this.formatZeit(datum.getTimeInMillis(), 5));
		mv.addObject("monat", lMonat);
		mv.setViewName("arbeitszeit");
		return mv;
	}
	
	/***
	 * 
	 * Function to a formated array of a work day
	 * 
	 * @param datum
	 * @param mit_id
	 * @return
	 */
	private ArbeitstagOutput getTag(Date datum, Integer mit_id){
		//Arbeitstag
		Arbeitstag atag = arbeitstagDao.findByDate(datum, mit_id);
		ArbeitstagOutput outputAtag = new ArbeitstagOutput();
		//Anwesenheitszeit in ms
		long tag_zeit = 0;
		long zoneOffset = Calendar.getInstance().getTimeZone().getOffset(0);
		Calendar jetzt = new GregorianCalendar();
		jetzt.set(1970, 0, 1);
		if(atag == null){
			outputAtag.setsZeit(this.formatZeit(tag_zeit - zoneOffset, 3));
			outputAtag.setZeit(tag_zeit - zoneOffset);
			outputAtag.setDatum(this.formatZeit(datum.getTime(), 1));
			return outputAtag;
		}else if(atag.getAtag_bis() != null){
			tag_zeit = atag.getAtag_bis().getTime() - atag.getAtag_von().getTime();
			outputAtag.setAtag_bis(this.formatZeit(atag.getAtag_bis().getTime(), 2));
		}else{
			// bis jetzt gearbeitet
			tag_zeit = jetzt.getTimeInMillis() - atag.getAtag_von().getTime();
		}
		List<Pausen> pausen = pausenDao.findByAtag(atag.getId());
		for(Pausen p : pausen){
			if(p.getPause_stop() != null){
				tag_zeit -= p.getPause_stop().getTime() - p.getPause_start().getTime();
			}else{
				tag_zeit -= jetzt.getTimeInMillis() - p.getPause_start().getTime();
			}
		}
		
		outputAtag.setsZeit(this.formatZeit(tag_zeit - zoneOffset, 3));
		outputAtag.setZeit(tag_zeit);
		outputAtag.setAtag_von(this.formatZeit(atag.getAtag_von().getTime(), 2));
		outputAtag.setDatum(this.formatZeit(datum.getTime(), 1));
		
		return outputAtag;
	}
	
	/***
	 * 
	 * Function format a time stamp for output
	 * 
	 * @param z
	 * @param type
	 * @return
	 */
	private String formatZeit(long z, Integer type){
		Calendar zeit = Calendar.getInstance();
		zeit.setTimeInMillis(z);
		String output;
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.GERMAN);
		format.setCalendar(zeit);
		switch(type){
		case 1:
			format.applyPattern("dd.MM.yyyy");
			output = format.format(zeit.getTime());
			break;
		case 2:
			format.applyPattern("HH:mm:ss");
			output = format.format(zeit.getTime());
			break;
		case 3:
			format.applyPattern("HH:mm");
			output = format.format(zeit.getTime());
			break;
		case 4:
			long h = z / 3600000;
			format.applyPattern("mm");
			output = h+":"+format.format(zeit.getTime());
			break;
		case 5:
			format.applyPattern("MMM yyyy");
			output = format.format(zeit.getTime());
			break;
		default:
			output = "###ERROR###"; 
			break;
		}

		return output;
	}
	
	/***
	 * 
	 * Function returns the amount of hours a employee has to work
	 * 
	 * @param cal
	 * @param mit_id
	 * @return
	 */
	private int getMonatSoll(Calendar cal, Integer mit_id){
		int monat_soll = 0;
		cal.set(Calendar.DAY_OF_MONTH, 1);
		Calendar firstDay = Calendar.getInstance();
		firstDay.setTime(cal.getTime());
		List<Integer> freeDay = new ArrayList<Integer>();
		for(int i = 0; i < cal.getActualMaximum(Calendar.DAY_OF_MONTH); i++){
			if(this.freeDay(cal, mit_id)){
				freeDay.add(cal.get(Calendar.DAY_OF_MONTH));
			}				
			cal.add(Calendar.DAY_OF_MONTH, 1);
		}
		Mitarbeiter mit = mitarbeiterDao.findById(mit_id);
		int soll_stunden;
		try{
			soll_stunden = mit.getMit_sollstunden();
		}catch (Exception e) {
			soll_stunden = 0;
		}
		monat_soll = (firstDay.getActualMaximum(Calendar.DAY_OF_MONTH) - freeDay.size()) * soll_stunden;
		return monat_soll;
	}
	
	/***
	 * 
	 * Function checks if a day is a working day
	 * 
	 * @param datum
	 * @param mit_id
	 * @return
	 */
	private boolean freeDay(Calendar datum, Integer mit_id){
		if(datum.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || datum.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)
			return true;
		else if(feiertageDao.findById(datum.getTime()) != null)
			return true;
		else if(urlaubDao.checkDate(datum.getTime(), mit_id))
			return true;
		else if(krankheitDao.checkDate(datum.getTime(), mit_id))
			return true;
		return false;
	}
}


